﻿using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;

namespace YBOT_Field_Control
{
    public class Game

    {
        #region Board and Relay Variables
            public int maxTowerNum = 10;        //Total # of towers in game
            public int bell = 2;                //Bell relay
            public int buzzer = 3;              //Buzzer relay
            public int controlBoard = 15;       //Control Board tower number
            public Label[] gLL = new Label[11]; //Field Display Lights
            public string xbPort = "COM4";      //Defaul XBee Com Port
        #endregion

        #region Game and Scoring Variables
            OneWire g1w;                        //One Wire constructor
            XBee gXB;                           //Xbee Constructor
            public string time =                //Time of day stamp
                DateTime.Now.Hour.ToString() + "_" 
                + DateTime.Now.Minute.ToString() + "_" 
                + DateTime.Now.Second.ToString();
            public int gameCycleCount = 0;      //Number of times the game has been started after the program is loaded
            public TeamVariables red = new TeamVariables("red");        //New team 
            public TeamVariables green = new TeamVariables("green");    //New team

            public int autoModeTime = 15;   //Autonomous Mode time in secs
            public int penaltyPoint = 1;    //Penalty point value awarded to other team
            public int feedScore = 6;       //Point value for feed the chicken game
            public int autoMax = 6;         //Max number of scores in autonomous


            //Game flags
            public bool gameDone = false;       //True when game has finished
            public bool STOP = false;           //True when game has been stopped
            public bool autoMode = false;       //True when game is in autonomous mode
            public bool practiceMode = false;   //True when game is in practice mode
        #endregion 

         #region Constructors

            public Game()
            {
                this.g1w = new OneWire();
            }

            public Game(OneWire g1w)
            {
                this.g1w = g1w;
            }

            public Game(XBee gXB)
        {
            this.gXB = gXB;
        }

            public Game(OneWire g1w, XBee gXB)
        {
            this.g1w = g1w;
            this.gXB = gXB;
        }

            public Game(OneWire g1w, XBee gXB, Label[] gLL)
        {
            this.g1w = g1w;
            this.gXB = gXB;
            this.gLL = gLL;
        }

        #endregion

        //Initiate game class
        public void begin()
        {
            red.setTowers(3, 3, 2, 4, 5, 1, g1w, gXB);      //Define Red team variables
            green.setTowers(8, 8, 7, 9, 10, 6, g1w, gXB);   //Define Green Team variables
            red.reset();                                    //Reset Red variables
            green.reset();                                  //Reset Green variables
        }

        /// <summary>
        /// Start a new game
        /// </summary>
        public void GameStartUp()
        {
            //Turn on all Hub Channel
            g1w.HubAllMainsOn();

            //Reset all variable
            gXB.Startup(xbPort);
            begin();
            autoMax = 6;

            //Set starting towers
            red.tower.randomTower = red.tower.yellowFeedTower;
            green.tower.randomTower = green.tower.yellowFeedTower;
            red.tower.randomLight = red.tower.blueLight;
            green.tower.randomLight = green.tower.blueLight;

            //Turn off all relays on all field towers
            g1w.AllTowersOff(maxTowerNum);

            //Ring bell
            g1w.RelayOn(bell, controlBoard);
            g1w.RelayOff(bell, controlBoard);
            Thread.Sleep(300);
            g1w.RelayOn(bell, controlBoard);
            g1w.RelayOff(bell, controlBoard);

            //Turn on All Field Lights
            AllTowersFlash();
            //Turn off All Field Lights
            AllTowersOffSafe();

            //Clear OneWire Activity Status on all towers
            g1w.ResetAllActivityLatches(maxTowerNum);
            GameLog("Tower and Latches Reset");

            //Turn on Robot Transmiters
            g1w.RelayOn(red.tower.controllerRelay, red.tower.controlTower);
            GameLog("Red Control On");
            g1w.RelayOn(green.tower.controllerRelay, green.tower.controlTower);
            GameLog("Green Control On");

            GameLog("Game Start");

            //If not practice mode then turn on the feeder towers
            if (!practiceMode)
            {
                g1w.RelayOn(red.tower.randomLight, red.tower.randomTower);
                g1w.RelayOff(green.tower.randomLight, green.tower.randomTower);
            }

        }

        /// <summary>
        /// End a Game
        /// </summary>
        public void GameShutDown()
        {
            //Turn on all Hub Channel
            //g1w.HubAllMainsOn();

            //Sound buzzer
            g1w.RelayOn(buzzer, controlBoard);
            Thread.Sleep(750);
            g1w.RelayOff(buzzer, controlBoard);

            //Turn off all towers
            g1w.AllTowersOff(maxTowerNum);
            GameLog("Tower Reset");
            GameLog("Game End");

            //Turn off OneWire Hub
            g1w.HubAllOff();

            //Close XB port
            gXB.Shutdown();
        }
        
        /// <summary>
        /// Main Game control :  enters and exits game modes
        /// </summary>
        public void MainGame()
        {
            string gamePath =  g1w.YBOTFilePath() + @"\Logs\Games_" + time;    //Sets path for game files
            //Try and create game path if it doesn't exist; set as null if it can't
            try
            {
                if (!Directory.Exists(gamePath)) Directory.CreateDirectory(gamePath); 
            }
            catch
            {
                gamePath = null;
            }

            //Do loop until the game is over or stopped
            while (!STOP && !gameDone)          
            {
                //If game is NOT in Autonomous mode & autonomous Max allowed button presses = 6
                if (!autoMode && autoMax == 6)
                {
                        //Change Transmitters to Driver Mode
                        g1w.RelayOn(red.tower.auto_driverRelay, red.tower.controlTower);
                        g1w.RelayOn(green.tower.auto_driverRelay, green.tower.controlTower);

                        //Ring bell
                        g1w.RelayOn(bell, controlBoard);
                        g1w.RelayOff(bell, controlBoard);
                        Thread.Sleep(300);
                        g1w.RelayOn(bell, controlBoard);
                        g1w.RelayOff(bell, controlBoard);

                        GameLog("Autonomous Mode Over");

                        //Change max button presses to 2
                        autoMax = 2;
                }

                //If red or green teams have not finished Autonomous Mode then enter AutoMode
                if (!green.autoFinished || !red.autoFinished || autoMode) AutoMode();

                //If red or green has finished Autonomous Mode and Autonomous Mode has finished
                if ((green.autoFinished || red.autoFinished) && !autoMode)
                {
                    //If green finished automode but hasn't entered CandleMode reset green CandleMode variables
                    if (!green.candleStart && green.autoFinished)
                    {
                        green.candle.candleReset();
                        green.candleStart = true;;
                    }
                    //If red finished automode but hasn't entered CandleMode reset red CandleMode variables
                    if (!red.candleStart && red.autoFinished)
                    {
                        red.candle.candleReset();
                        red.candleStart = true;
                    }
                    //Enter Candle Mode
                    CandleMode();
                }
                Application.DoEvents();         //Do window's stuff
                return;                         //Return to control program
            }
        }

        /// <summary>
        /// Autonomous Mode
        /// </summary>
        public void AutoMode()
        {
            #region Red Autonomous

            //If red team has finished Autonomous Mode
            if (!red.autoFinished)
            {
                //If red team has scored need number of feeder buttons turn off feeder towers and finish Autonomous Mode
                if (red.autoCount >= autoMax)
                {
                    red.autoFinished = true;
                    g1w.AllRelaysOff(red.tower.randomTower);
                }
                else
                {
                    //Check Random Feeder Tower's Activity Latch Status
                    g1w.ActivityLatchStatus(red.tower.randomTower);
                    //If a button has been pressed
                    if (red.tower.buttonPress(red.tower.randomTower))
                    {
                        //If both buttons have NOT been pressed
                        if (!(red.tower.bluePress && red.tower.yellowPress))
                        {
                            //If blue button has been pressed and the random light is blue
                            if (red.tower.bluePress && (red.tower.randomLight == red.tower.blueLight))
                            {   
                                red.autoCount++;                                            //Increase button press count
                                red.score = red.score + feedScore;                          //Add autonomous points to red score
                                GameLog("Red Auto-Hit - Score = " + red.score.ToString());        //Record Score
                                if (red.autoCount < autoMax) red.tower.flipFeedTower();     //If less than needed button presses swap feeder towers and light a new random buton
                            }
                            //Else if yellow button has been pressed and the random light is yellow
                            else if (red.tower.yellowPress && (red.tower.randomLight == red.tower.yellowLight))
                            {
                                red.autoCount++;                                            //Increase button press count
                                red.score = red.score + feedScore;                          //Add autonomous points to red score
                                GameLog("Red Auto-Hit - Score = " + red.score.ToString());        //Record Score
                                if (red.autoCount < autoMax) red.tower.flipFeedTower();     //If less than needed button presses swap feeder towers and light a new random buton
                            }
                            //If the wrong button has been pressed 
                            else
                            {
                                //Score for the green team and flip feeder tower and light a random light
                                green.score = green.score + penaltyPoint;
                                GameLog("Red Auto-Missed" + "\r\n" + "Green Auto-Score = " + green.score.ToString());
                                red.tower.flipFeedTower();
                            }
                        }
                        //Else if both button were pressed
                        else
                        {
                            //Score for the green team and flip feeder tower and light a random light
                            green.score = green.score + penaltyPoint;
                            GameLog("Red Auto-Missed" + "\r\n" + "Green Auto-Score = " + green.score.ToString());
                            red.tower.flipFeedTower();
                        }
                    }
                }
            }

            #endregion

            #region Green Autonomous

            if (!green.autoFinished)
            {
                if (green.autoCount >= autoMax)
                {
                    green.autoFinished = true;
                    g1w.AllRelaysOff(green.tower.randomTower);
                }
                else
                {
                    g1w.ActivityLatchStatus(green.tower.randomTower);
                    if (green.tower.buttonPress(green.tower.randomTower))
                    {
                        if (!(green.tower.bluePress && green.tower.yellowPress))
                        {
                            if (green.tower.bluePress && (green.tower.randomLight == green.tower.blueLight))
                            {
                                green.autoCount++;
                                green.score = green.score + feedScore;
                                GameLog("Green Auto-Hit - Score = " + green.score.ToString());
                                if (green.autoCount < autoMax) green.tower.flipFeedTower();
                            }
                            else if (green.tower.yellowPress && (green.tower.randomLight == green.tower.yellowLight))
                            {
                                green.autoCount++;
                                green.score = green.score + feedScore;
                                GameLog("Green Auto-Hit - Score = " + green.score.ToString());
                                if (green.autoCount < autoMax) green.tower.flipFeedTower();
                            }
                            else
                            {
                                red.score = red.score + penaltyPoint;
                                GameLog("Green Auto-Missed" + "\r\n" + "Red Auto-Score = " + red.score.ToString());
                                green.tower.flipFeedTower();
                            }
                        }
                        else
                        {
                            red.score = red.score + penaltyPoint;
                            GameLog("Green Auto-Missed" + "\r\n" + "Red Auto-Score = " + red.score.ToString());
                            green.tower.flipFeedTower();
                        }
                    }

                }
            }

            #endregion
        }

        /// <summary>
        /// Candle Mode
        /// </summary>
        public void CandleMode()
        {

            #region Red Candle

            if (red.autoFinished)
            {
                //If Eggs have been counted check the candle station for button press
                if (red.candle.eggsCounted)
                {
                    g1w.ActivityLatchStatus(red.tower.candleTower);         //Check Activity Status of selected tower
                    if (red.tower.buttonPress(red.tower.candleTower))       //If button is pressed
                    {
                        red.candle.candleEgg();                             //Select corner tower
                    }
                }
                //Else count eggs and check feed towers for button press
                else
                {
                    g1w.ActivityLatchStatus(red.tower.randomTower);         //Check Activity Status of selected tower
                    //If button is pressed
                    if (red.tower.buttonPress(red.tower.randomTower))
                    {


                        //If blue button is pressed and random light = blue
                        if (red.tower.bluePress && (red.tower.randomLight == red.tower.blueLight))
                        {

                            int redEggNum = red.candle.countEggs();     //Get number of eggs under selected tower
                            red.candle.candleReset();   //Reset candle mode
                            string redEggs = "Red Eggs = " + redEggNum.ToString();

                            //If too many eggs
                            if (red.candle.descore)
                            {
                                green.score = green.score + penaltyPoint;                                               //Score penalty point for Green
                                GameLog("Red To Many Eggs" + "\r\n" + "Green Score = " + green.score.ToString());       //Record Score
                            }
                            //Else team does not too many eggs
                            else
                            {
                                red.score = red.score + redEggNum;     //Add number of eggs under tower to red score
                                GameLog("Red Score = " + red.score.ToString());     //Record Score
                            }
                        }
                        //If yellow button is pressed and random light = yellow
                        else if (red.tower.yellowPress && (red.tower.randomLight == red.tower.yellowLight))
                        {
                            int redEggNum = red.candle.countEggs();     //Get number of eggs under selected tower
                            red.candle.candleReset();   //Reset candle mode
                            string redEggs = "Red Eggs = " + redEggNum.ToString();

                            //If too many eggs
                            if (red.candle.descore)
                            {
                                green.score = green.score + penaltyPoint;                                               //Score penalty point for Green
                                GameLog("Red To Many Eggs" + "\r\n" + "Green Score = " + green.score.ToString());       //Record Score
                            }
                            //Else team does not too many eggs
                            else
                            {
                                red.score = red.score + redEggNum;     //Add number of eggs under tower to red score
                                GameLog("Red Score = " + red.score.ToString());     //Record Score
                            }
                        }
                    }
                }
            }
            #endregion

            #region Green Candle

            if (green.autoFinished)
            {
                //If Eggs have been counted check the candle station for button press
                if (green.candle.eggsCounted)
                {
                    g1w.ActivityLatchStatus(green.tower.candleTower);       //Check Activity Status of selected tower
                    if (green.tower.buttonPress(green.tower.candleTower))   //If button is pressed
                    {
                        green.candle.candleEgg();                           //Select corner tower
                    }
                }
                //Else count eggs and check feed towers for button press
                else
                {
                    g1w.ActivityLatchStatus(green.tower.randomTower);       //Check Activity Status of selected tower
                    //If button is pressed
                    if (green.tower.buttonPress(green.tower.randomTower))
                    {


                        //If blue button is pressed and random light = blue
                        if (green.tower.bluePress && (green.tower.randomLight == green.tower.blueLight))
                        {
                            int greenEggNum = green.candle.countEggs();       //Get number of eggs on tower
                            green.candle.candleReset();     //Reset candle mode
                            string greenEggs = "Green Eggs = " + greenEggNum.ToString();

                            //If too many eggs
                            if (green.candle.descore)
                            {
                                red.score = red.score + penaltyPoint;                                               //Score penalty point for Red
                                GameLog("Geen To Many Eggs" + "\r\n" + "Red Score = " + red.score.ToString());      //Log Score
                            }
                            //else team does not have too many eggs
                            else
                            {
                                green.score = green.score + greenEggNum;       //Add number of eggs under tower to green score
                                GameLog("Green Score = " + green.score.ToString());         //Log Score
                            }
                        }
                        //If yellow button is pressed and random light = yellow
                        else if (green.tower.yellowPress && (green.tower.randomLight == green.tower.yellowLight))
                        {
                            int greenEggNum = green.candle.countEggs();       //Get number of eggs on tower
                            green.candle.candleReset();     //Reset candle mode
                            string greenEggs = "Green Eggs = " + greenEggNum.ToString();

                            //If too many eggs
                            if (green.candle.descore)
                            {
                                red.score = red.score + penaltyPoint;                                               //Score penalty point for Red
                                GameLog("Geen To Many Eggs" + "\r\n" + "Red Score = " + red.score.ToString());      //Log Score
                            }
                            //else team does not have too many eggs
                            else
                            {
                                green.score = green.score + greenEggNum;       //Add number of eggs under tower to green score
                                GameLog("Green Score = " + green.score.ToString());         //Log Score
                            }
                        }
                    }
                }
            }
            #endregion

            //If green doesn't make a mistake
            if (green.candle.perfectScore == 12)
            {
                green.score = green.score + 12;                                     //Add 12 points to green score
                GameLog("Green Perfect Candling : " + green.score.ToString());      //Log bonus
                green.candle.perfectScore++;                                        //Increment perfectScore to prevent scoring again
            }
            //If red doesn't make a mistake
            if (red.candle.perfectScore == 12)
            {
                red.score = red.score + 12;                                         //Add 12 points to red score
                GameLog("Red Perfect Candling " + red.score.ToString());            //Log bonus
                red.candle.perfectScore++;                                          //Increment perfectScore to prevent scoring again
            }

        }

        /// <summary>
        /// Used to turn on all tower lights safely
        /// </summary>
        public void AllTowersFlash()
        {

            //Repeat for every tower 
            for (int i = 1; i <= maxTowerNum; i++)
            {

            byte relayBuffer = 255;                                             //Buffer relay all 1s

            if (i == 2 || i == 3 || i == 4 || i == 7 || i == 8 || i == 9)       //If one of these towers 
            {
                relayBuffer = g1w.BuildRelayState(4, 0, relayBuffer);           //Set relay state: all off controller/reset relay on 
                relayBuffer = g1w.BuildRelayState(5, 0, relayBuffer);           //Set relay state: all off controller and driver on
            }

            g1w.SetTowerState(relayBuffer, i);                                  //Set tower to current relay state

            }
        }

        /// <summary>
        /// Used to turn off all Relays on all towers without changing the robot controller state
        /// </summary>
        public void AllTowersOffSafe()
        {
            byte relayBuffer = 0;                                           //Set realy buffer 1 to all 0s
            byte relayBuffer2 = 0;                                          //Set realy buffer 2 to all 0s
            relayBuffer = g1w.BuildRelayState(4, 1, relayBuffer);           //Set relay state: all off controller/reset relay on 

            if (autoMode) relayBuffer2 = relayBuffer;                       //If game is in automode relay buffer 2 = buffer 1
            else relayBuffer2 = g1w.BuildRelayState(5, 1, relayBuffer);     //Set relay state: all off controller and drivermode on

            //Change state of tower
            g1w.AllRelaysOff(1);                                            
            g1w.SetTowerState(relayBuffer, 2);
            g1w.SetTowerState(relayBuffer2, 3);      
            g1w.SetTowerState(relayBuffer, 4);
            g1w.AllRelaysOff(5);
            g1w.AllRelaysOff(6);
            g1w.SetTowerState(relayBuffer, 7);
            g1w.SetTowerState(relayBuffer2, 8);      
            g1w.SetTowerState(relayBuffer, 9);
            g1w.AllRelaysOff(10);

        }

        /// <summary>
        /// Writes text to log file
        /// </summary>
        /// <param name="text">Text as string</param>
        public void GameLog(string text)
        {
            string gamePath =  g1w.YBOTFilePath() + @"\Logs\Games_" + time;             //Sets path for game files

            string file = "\\Game#" + gameCycleCount.ToString() + ".txt";               //File name 
            try
            {
                if (!Directory.Exists(gamePath)) Directory.CreateDirectory(gamePath);   //If path doesn't exist 
                string _date = DateTime.Today.ToShortDateString();                      //Get date
                string _time = DateTime.Now.ToLongTimeString();                         //Get time
                text = (_date + " " + _time + " " + text);                              //Build string to record
                FileStream fs = new FileStream((gamePath + file), FileMode.Append, FileAccess.Write, FileShare.Write);      //Open file
                fs.Close();
                StreamWriter sw = new StreamWriter((gamePath + file), true, Encoding.ASCII);
                sw.WriteLine(text);     //Write string
                sw.Close();             //Close file
            }
            catch
            {
                return;
            }
        }

    }
}
